#ifndef THREAD_SAFE_LIST_H
#define THREAD_SAFE_LIST_H

#include <list>
#include <mutex>
#include <exception>

template <typename T>
class ThreadSafeList {
private:
    std::list<T> list;
    mutable std::mutex mutex;

public:
    void push_back(const T& value);
    void push_back_all(const T* values, const int nums);
    bool pop_front(T& value);
    T   pop_front();
    T& back();
    T& front();
    void clear();
    size_t size() const;
    bool empty() const;
    std::list<T> getList();
    // T& operator[](int index);
};

// template <typename T>
// T& ThreadSafeList<T>::operator[](int index){
//     //std::lock_guard<std::mutex> lock(mutex);
//     if (list.empty()) {
//         throw std::runtime_error("Trying to access back of an empty list");
//     }
//     T a = list[index];
//     return a;
// }
template <typename T>
std::list<T> ThreadSafeList<T>::getList() {
    std::lock_guard<std::mutex> lock(mutex);
    return list;
}

template <typename T>
void ThreadSafeList<T>::push_back(const T& value) {
    std::lock_guard<std::mutex> lock(mutex);
    list.push_back(value);
}

template <typename T>
void ThreadSafeList<T>::push_back_all(const T * values, const int nums) {
    std::lock_guard<std::mutex> lock(mutex);
    for (int i = 0; i < nums; i++) {
        list.push_back(values[i]);
    }
}

template <typename T>
bool ThreadSafeList<T>::pop_front(T& value) {
    std::lock_guard<std::mutex> lock(mutex);
    if (list.empty()) {
        return false;
    }
    value = list.front();
    list.pop_front();
    return true;
}

template <typename T>
T ThreadSafeList<T>::pop_front() {
    std::lock_guard<std::mutex> lock(mutex);
    // if (list.empty()) {
    //     return nullptr;
    // }
    T value = list.front();
    list.pop_front();
    return value;
}

template <typename T>
T& ThreadSafeList<T>::back() {
    std::lock_guard<std::mutex> lock(mutex);
    if (list.empty()) {
        throw std::runtime_error("Trying to access back of an empty list");
    }
    return list.back();
}

template <typename T>
T& ThreadSafeList<T>::front() {
    std::lock_guard<std::mutex> lock(mutex);
    if (list.empty()) {
        throw std::runtime_error("Trying to access back of an empty list");
    }
    return list.front();
}

template <typename T>
void ThreadSafeList<T>::clear() {
    std::lock_guard<std::mutex> lock(mutex);
    list.clear();
}

template <typename T>
size_t ThreadSafeList<T>::size() const {
    std::lock_guard<std::mutex> lock(mutex);
    return list.size();
}

template <typename T>
bool ThreadSafeList<T>::empty() const {
    std::lock_guard<std::mutex> lock(mutex);
    return list.empty();
}


#endif // THREAD_SAFE_LIST_H
